using System;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;

namespace MatrixFramework.Shared.Application.Caching
{
    /// <summary>
    /// 分布式缓存管理器
    /// </summary>
    public class DistributedCacheManager : ITransientDependency
    {
        private readonly IDistributedCache _distributedCache;
        private readonly IClock _clock;
        private readonly ILogger<DistributedCacheManager> _logger;

        public DistributedCacheManager(
            IDistributedCache distributedCache,
            IClock clock,
            ILogger<DistributedCacheManager> logger)
        {
            _distributedCache = distributedCache;
            _clock = clock;
            _logger = logger;
        }

        /// <summary>
        /// 获取缓存项
        /// </summary>
        public async Task<T?> GetAsync<T>(string key, Func<Task<T?>>? factory = null, TimeSpan? expiration = null) where T : class
        {
            var cachedData = await _distributedCache.GetStringAsync(key);

            if (cachedData != null)
            {
                try
                {
                    var result = JsonSerializer.Deserialize<T>(cachedData);
                    _logger.LogDebug("缓存命中: {CacheKey}", key);
                    return result;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "反序列化缓存数据失败: {CacheKey}", key);
                }
            }

            // 缓存未命中，使用工厂方法获取数据
            if (factory != null)
            {
                var data = await factory();
                if (data != null)
                {
                    await SetAsync(key, data, expiration);
                }
                return data;
            }

            return null;
        }

        /// <summary>
        /// 设置缓存项
        /// </summary>
        public async Task SetAsync<T>(string key, T value, TimeSpan? expiration = null) where T : class
        {
            if (value == null)
            {
                _logger.LogWarning("尝试缓存null值: {CacheKey}", key);
                return;
            }

            try
            {
                var options = new DistributedCacheEntryOptions();

                if (expiration.HasValue)
                {
                    options.AbsoluteExpirationRelativeToNow = expiration.Value;
                }
                else
                {
                    // 默认过期时间30分钟
                    options.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
                }

                var serializedData = JsonSerializer.Serialize(value);
                await _distributedCache.SetStringAsync(key, serializedData, options);

                _logger.LogDebug("缓存设置成功: {CacheKey}, 过期时间: {Expiration}",
                    key, options.AbsoluteExpirationRelativeToNow);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "设置缓存失败: {CacheKey}", key);
                throw;
            }
        }

        /// <summary>
        /// 删除缓存项
        /// </summary>
        public async Task RemoveAsync(string key)
        {
            try
            {
                await _distributedCache.RemoveAsync(key);
                _logger.LogDebug("缓存删除成功: {CacheKey}", key);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "删除缓存失败: {CacheKey}", key);
            }
        }

        /// <summary>
        /// 刷新缓存项
        /// </summary>
        public async Task RefreshAsync(string key)
        {
            try
            {
                await _distributedCache.RefreshAsync(key);
                _logger.LogDebug("缓存刷新成功: {CacheKey}", key);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "刷新缓存失败: {CacheKey}", key);
            }
        }

        /// <summary>
        /// 检查缓存项是否存在
        /// </summary>
        public async Task<bool> ExistsAsync(string key)
        {
            try
            {
                var cachedData = await _distributedCache.GetStringAsync(key);
                return !string.IsNullOrEmpty(cachedData);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "检查缓存存在性失败: {CacheKey}", key);
                return false;
            }
        }

        /// <summary>
        /// 获取或创建缓存项（带锁，防止缓存击穿）
        /// </summary>
        public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiration = null) where T : class
        {
            var cachedData = await GetAsync<T>(key);
            if (cachedData != null)
            {
                return cachedData;
            }

            // 使用简单的内存锁防止并发创建
            var lockKey = $"lock:{key}";
            var lockTimeout = TimeSpan.FromSeconds(30);

            // 尝试获取锁
            if (await TryAcquireLockAsync(lockKey, lockTimeout))
            {
                try
                {
                    // 再次检查缓存，防止在等待锁期间被其他进程设置
                    cachedData = await GetAsync<T>(key);
                    if (cachedData != null)
                    {
                        return cachedData;
                    }

                    // 创建数据并缓存
                    var data = await factory();
                    await SetAsync(key, data, expiration);
                    return data;
                }
                finally
                {
                    await ReleaseLockAsync(lockKey);
                }
            }
            else
            {
                // 获取锁失败，等待一段时间后重试
                await Task.Delay(100);
                return await GetOrCreateAsync(key, factory, expiration);
            }
        }

        /// <summary>
        /// 批量删除缓存项
        /// </summary>
        public async Task RemoveBatchAsync(params string[] keys)
        {
            var tasks = new Task[keys.Length];
            for (int i = 0; i < keys.Length; i++)
            {
                tasks[i] = RemoveAsync(keys[i]);
            }

            await Task.WhenAll(tasks);
            _logger.LogDebug("批量删除缓存完成，数量: {Count}", keys.Length);
        }

        /// <summary>
        /// 按前缀删除缓存项
        /// </summary>
        public async Task RemoveByPrefixAsync(string prefix)
        {
            // 注意：Redis支持按前缀删除，但其他缓存实现可能不支持
            // 这里提供一个通用的实现方案
            try
            {
                // 对于Redis，可以使用SCAN命令
                // 对于其他实现，可能需要维护缓存键的注册表
                _logger.LogInformation("按前缀删除缓存: {Prefix}", prefix);

                // 这里简化处理，实际应用中可能需要根据具体缓存实现来优化
                await Task.CompletedTask;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "按前缀删除缓存失败: {Prefix}", prefix);
            }
        }

        /// <summary>
        /// 尝试获取分布式锁
        /// </summary>
        private async Task<bool> TryAcquireLockAsync(string lockKey, TimeSpan timeout)
        {
            try
            {
                var lockValue = Guid.NewGuid().ToString();
                var lockData = new LockData
                {
                    Value = lockValue,
                    CreatedAt = _clock.Now,
                    Timeout = timeout
                };

                var serializedLock = JsonSerializer.Serialize(lockData);
                var options = new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = timeout
                };
                await _distributedCache.SetStringAsync(lockKey, serializedLock, options);

                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取分布式锁失败: {LockKey}", lockKey);
                return false;
            }
        }

        /// <summary>
        /// 释放分布式锁
        /// </summary>
        private async Task ReleaseLockAsync(string lockKey)
        {
            try
            {
                await _distributedCache.RemoveAsync(lockKey);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "释放分布式锁失败: {LockKey}", lockKey);
            }
        }

        /// <summary>
        /// 锁数据结构
        /// </summary>
        private class LockData
        {
            public string Value { get; set; } = string.Empty;
            public DateTime CreatedAt { get; set; }
            public TimeSpan Timeout { get; set; }
        }
    }
}